using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Champ
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class GameController : Microsoft.Xna.Framework.Game
    {
        //Default needed variables
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        
        //Makes coding easier and easier to read, trust me
        public enum gameState {mainMenu, choosePlayer, startTurn, getHelp, backStabbers, fight, winLose, loot, inventory, endgame, credits};
        public enum controllerButtons { A, B, X, Y, Start, Back, LBump, RBump, DLeft, DRight, DUp, DDown };
        //Current state of the game, Starts out at main menu surprisingly enough :o 
        public gameState currentGameState = gameState.mainMenu;
        public gameState previousGameState;
        //Useful data to keep
        public int currentMonster = 0;
        static int numOfMonsters = 50;
        public int playersTurn = 1;
        public int outcome = 0;
       
        
        //Textures
        static int numOfFonts = 26;
        static int numOfPlayerTextures = 4;
        static int numOfMonsterTextures = 15;
        static int possibleMonsters = 14;
        static int numOfScreenTextures = 7;
        static int numOfItemTextures = 0;
        public Texture2D[] playerTextures = new Texture2D[numOfPlayerTextures];
        public Texture2D[] monsterTextures = new Texture2D[numOfMonsterTextures];
        public Texture2D[] screenTextures = new Texture2D[numOfScreenTextures];
        public Texture2D[] itemTextures = new Texture2D[numOfItemTextures];
        public Texture2D[] buttonTextures = new Texture2D[6];
        public SpriteFont[] gameFont = new SpriteFont[numOfFonts];
        //The main things in the game
        public Monster[] monsters = new Monster[numOfMonsters];
        public Player[] player = new Player[4];
        public bool paused = false;
        Screen currentScreen;

        //Region used to resize sprites to the display field
        public Rectangle titleSafe;

        Random random = new Random();
       
     
        public GameController()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            
            
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            
            //Loading textures by type of in game object they represent
            for (int playerTexNum = 0; playerTexNum < numOfPlayerTextures; playerTexNum++)
            {
                playerTextures[playerTexNum] = Content.Load<Texture2D>("Player images/playerImage"+(playerTexNum+1));
            }
            for (int monsterTexNum = 0; monsterTexNum < numOfMonsterTextures; monsterTexNum++)
            {
                monsterTextures[monsterTexNum] = Content.Load<Texture2D>("Monster images/monsterImage" + (monsterTexNum+1));
            }
            for (int screenTexNum = 0; screenTexNum < numOfScreenTextures; screenTexNum++)
            {
                screenTextures[screenTexNum] = Content.Load<Texture2D>("Screen images/screenImage" + (screenTexNum+1));
            }
            for (int itemTexNum = 0; itemTexNum < numOfItemTextures; itemTexNum++)
            {
                itemTextures[itemTexNum] = Content.Load<Texture2D>("Item images/itemImage" + (itemTexNum+1));
            }
            for (int fontNumber = 0; fontNumber < numOfFonts; fontNumber++)
            {
                gameFont[fontNumber] = Content.Load<SpriteFont>("Font/gameFont" + (fontNumber + 1));
            }
            buttonTextures[0] = Content.Load<Texture2D>("buttonTextures/xboxControllerButtonA");
            buttonTextures[1] = Content.Load<Texture2D>("buttonTextures/xboxControllerButtonB");
            buttonTextures[2] = Content.Load<Texture2D>("buttonTextures/xboxControllerButtonX");
            buttonTextures[3] = Content.Load<Texture2D>("buttonTextures/xboxControllerButtonY");
            buttonTextures[4] = Content.Load<Texture2D>("buttonTextures/xboxControllerStart");
            buttonTextures[5] = Content.Load<Texture2D>("buttonTextures/xboxControllerDPad");
            
            //Testing
            titleSafe = GetTitleSafeArea(1f);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }
        
        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            //Checks game state and calls proper controller functions
            if (currentGameState == gameState.mainMenu)
            {
                player[0] = null;
                player[1] = null;
                player[2] = null;
                player[3] = null;
                
                if(currentScreen == null)
                {
                    currentScreen = new MainScreen();
                    currentScreen.texture[0] = screenTextures[3];
                }
                else
                {
                    
                }
                    StartGame();
            }
            else if (currentGameState == gameState.choosePlayer)
            {

                if (currentScreen == null)
                {
                    currentScreen = new ChooseCharacterScreen();
                    currentScreen.texture[0] = screenTextures[2];
                }
                else
                {

                }
                ChoosePlayer();
            }
            else if (currentGameState == gameState.startTurn)
            {
                StartTurn();
            }
            else if (currentGameState == gameState.getHelp)
            {
                GetHelp();
                Pause();
            }
           
            else if (currentGameState == gameState.fight)
            {
                Fight();
            }
            else if (currentGameState == gameState.winLose)
            {
               
            }
            else if (currentGameState == gameState.loot)
            {
                Loot(playersTurn-1);
            }
            else if (currentGameState == gameState.inventory)
            {
                AdjustInventory();
            }
            else if (currentGameState == gameState.endgame)
            {
                Endgame();
            }

            //Temp
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            {
                this.Exit();
            }
           
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Brown);
            spriteBatch.Begin();
            currentScreen.DrawScreen(spriteBatch, this);
            spriteBatch.End();

            base.Draw(gameTime);
        }
        
        //Gets the safe area for displaying on the screen
        protected Rectangle GetTitleSafeArea(float percent)
        {
            Rectangle retval = new Rectangle(
                graphics.GraphicsDevice.Viewport.X,
                graphics.GraphicsDevice.Viewport.Y,
                graphics.GraphicsDevice.Viewport.Width,
                graphics.GraphicsDevice.Viewport.Height);

            // Find Title Safe area of Xbox 360.
            float border = (1 - percent) / 2;
            retval.X = (int)(border * retval.Width);
            retval.Y = (int)(border * retval.Height);
            retval.Width = (int)(percent * retval.Width);
            retval.Height = (int)(percent * retval.Height);
            return retval;
        }

       //Sets up a players turn
        private void StartTurn()
        {
            player[playersTurn - 1].done = true;
            player[playersTurn - 1].side = 1;
            player[playersTurn - 1].currentPlayerState = Player.playerState.playersTurn;
            player[playersTurn - 1].characterDisplayData(titleSafe, titleSafe);
            
            player[playersTurn % 4].currentPlayerState = Player.playerState.helpsFirst;
            player[playersTurn % 4].characterDisplayData(titleSafe, titleSafe);

            player[(playersTurn + 1)%4].currentPlayerState = Player.playerState.helpsSecond;
            player[(playersTurn + 1)%4].characterDisplayData(titleSafe, titleSafe);

            player[(playersTurn + 2)%4].currentPlayerState = Player.playerState.helpsThird;
            player[(playersTurn + 2)%4].characterDisplayData(titleSafe, titleSafe);
            
            currentGameState = gameState.getHelp;
        }

        //Gives players an oportunity to help or hurt the current player
        private void GetHelp()
        {
            if (paused)
            {

            }
            else
            {
                for (int i = 0; i < player.Length; i++)
                {
                    if (!player[i].done)
                    {
                        player[i].ChooseSide();
                    }
                }
                if (player[(playersTurn - 1) % 4].done)
                {
                    player[(playersTurn - 1) % 4].currentPlayerState = Player.playerState.playersTurn;
                    player[(playersTurn - 1) % 4].characterDisplayData(titleSafe, titleSafe);
                }
                if (player[(playersTurn) % 4].done)
                {
                    if (player[(playersTurn) % 4].side == 1)
                    {
                        player[(playersTurn) % 4].currentPlayerState = Player.playerState.helpsFirst;
                        player[(playersTurn) % 4].characterDisplayData(titleSafe, titleSafe);
                    }
                    else if (player[(playersTurn) % 4].side == 0)
                    {
                        player[(playersTurn) % 4].currentPlayerState = Player.playerState.neutralFirst;
                        player[(playersTurn) % 4].characterDisplayData(titleSafe, titleSafe);
                    }
                    else
                    {
                        player[(playersTurn) % 4].currentPlayerState = Player.playerState.againstFirst;
                        player[(playersTurn) % 4].characterDisplayData(titleSafe, titleSafe);
                    }
                }
                if (player[(playersTurn + 1) % 4].done)
                {
                    if (player[(playersTurn + 1) % 4].side == 1)
                    {
                        player[(playersTurn + 1) % 4].currentPlayerState = Player.playerState.helpsSecond;
                        player[(playersTurn + 1) % 4].characterDisplayData(titleSafe, titleSafe);
                    }
                    else if (player[(playersTurn + 1) % 4].side == 0)
                    {
                        player[(playersTurn + 1) % 4].currentPlayerState = Player.playerState.neutralSecond;
                        player[(playersTurn + 1) % 4].characterDisplayData(titleSafe, titleSafe);
                    }
                    else
                    {
                        player[(playersTurn + 1) % 4].currentPlayerState = Player.playerState.againstSecond;
                        player[(playersTurn + 1) % 4].characterDisplayData(titleSafe, titleSafe);
                    }
                }
                if (player[(playersTurn + 2) % 4].done)
                {
                    if (player[(playersTurn + 2) % 4].side == 1)
                    {
                        player[(playersTurn + 2) % 4].currentPlayerState = Player.playerState.helpsThird;
                        player[(playersTurn + 2) % 4].characterDisplayData(titleSafe, titleSafe);
                    }
                    else if (player[(playersTurn + 2) % 4].side == 0)
                    {
                        player[(playersTurn + 2) % 4].currentPlayerState = Player.playerState.neutralThird;
                        player[(playersTurn + 2) % 4].characterDisplayData(titleSafe, titleSafe);
                    }
                    else
                    {
                        player[(playersTurn + 2) % 4].currentPlayerState = Player.playerState.againstThird;
                        player[(playersTurn + 2) % 4].characterDisplayData(titleSafe, titleSafe);
                    }
                }
            }
            if (player[0].done && player[1].done && player[2].done && player[3].done)
            {
                currentGameState = gameState.fight;
            }
        }

        //Does fight calculations
        private void Fight()
        {
            //Add more to this once items are implemented
            player[0].assistedLevel = player[0].level;
            player[1].assistedLevel = player[1].level;
            player[2].assistedLevel = player[2].level;
            player[3].assistedLevel = player[3].level;
            monsters[currentMonster].assistedLevel = monsters[currentMonster].level;

            outcome = player[0].assistedLevel * player[0].side + player[1].assistedLevel * player[1].side + player[2].assistedLevel * player[2].side +
                   player[3].assistedLevel * player[3].side - monsters[currentMonster].assistedLevel;
            if (outcome > 0)
            {
                player[playersTurn - 1].level++;
                player[0].done = false;
                player[1].done = false;
                player[2].done = false;
                player[3].done = false;
                currentGameState = gameState.loot;
            }
            else
            {
                player[0].done = false;
                player[1].done = false;
                player[2].done = false;
                player[3].done = false;
                currentGameState = gameState.inventory;
                currentScreen = new ItemsScreen();
                currentScreen.texture[0] = screenTextures[1];
            }
            if (player[playersTurn - 1].level == 10)
            {
                currentGameState = gameState.endgame;
                currentScreen = new EndScreen();
                currentScreen.texture[0] = screenTextures[4];

            }
        }

        //Deals with the player choose screen
        private void ChoosePlayer()
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed)
            {
                player[0] = new Human();
                player[0].texture[0] = playerTextures[0];
                player[0].whichController = PlayerIndex.One;

            }
            if (GamePad.GetState(PlayerIndex.Two).Buttons.A == ButtonState.Pressed)
            {
                player[1] = new Human();
                player[1].texture[0] = playerTextures[0];
                player[2].whichController = PlayerIndex.Two;
            }
            if (GamePad.GetState(PlayerIndex.Three).Buttons.A == ButtonState.Pressed)
            {
                player[2] = new Human();
                player[2].texture[0] = playerTextures[0];
                player[2].whichController = PlayerIndex.Three;

            }
            if (GamePad.GetState(PlayerIndex.Four).Buttons.A == ButtonState.Pressed)
            {
                player[3] = new Human();
                player[3].texture[0] = playerTextures[0];
                player[3].whichController = PlayerIndex.Four;

            }
            if (player[0] != null)
            {
                ChooseImage(player[0]);
            }
            if (player[1] != null)
            {
                ChooseImage(player[1]);
            }
            if (player[2] != null)
            {
                ChooseImage(player[2]);
            }
            if (player[3] != null)
            {
                ChooseImage(player[3]);
            }

            for (int i = 0; i < player.Length; i++)
            {
                if (player[i] != null && player[i].CheckInputButtons(controllerButtons.Start))
                {
                    if (player[0] == null)
                {
                    player[0] = new AI(playerTextures);
                    ChooseImageAI(player[0]);
                }
                if (player[1] == null)
                {
                    player[1] = new AI(playerTextures);
                    ChooseImageAI(player[1]);
                }
                if (player[2] == null)
                {
                    player[2] = new AI(playerTextures);
                    ChooseImageAI(player[2]);
                }
                if (player[3] == null)
                {
                    player[3] = new AI(playerTextures);
                    ChooseImageAI(player[3]);
                }
                InitializeGame(); 
            
                }
            }                
        }

        //Waits until a player hits start at the main menu
        private void StartGame()
        {
            //Check for any player hitting start 
            if (GamePad.GetState(PlayerIndex.One).Buttons.Start == ButtonState.Pressed || GamePad.GetState(PlayerIndex.Two).Buttons.Start == ButtonState.Pressed
                || GamePad.GetState(PlayerIndex.Three).Buttons.Start == ButtonState.Pressed || GamePad.GetState(PlayerIndex.Four).Buttons.Start == ButtonState.Pressed)
            {
                //Continue to player select 
                currentGameState = gameState.choosePlayer;
                currentScreen = new ChooseCharacterScreen();
                currentScreen.texture[0] = screenTextures[2];
            }
        }

        //Deals with the inventory screen
        private void AdjustInventory()
        {
            for (int i = 0; i < player.Length; i++)
            {
                player[i].HandleInventory();
            }
            if (player[0].done && player[1].done && player[2].done && player[3].done)
            {
                MoveOn();
            }   
        }

        //Loots the monster
        private void Loot(int currentSelector)
        {
            for (int i = 0; i < player.Length; i++)
            {
                if(!player[(i+playersTurn-1)%4].done)
                {
                    player[(i + playersTurn - 1) % 4].Looting();
                    return;
                }
            }
            for (int i = 0; i < player.Length; i++)
            {
                player[i].done = false;
            }
            currentGameState = gameState.inventory;
            currentScreen = new ItemsScreen();
            currentScreen.texture[0] = screenTextures[1];
        }

        //Choosing the player 
        private void ChooseImage(Player currentPlayer)
        {
           if(currentPlayer.CheckInputButtons(controllerButtons.DLeft))
           {
                if (currentPlayer.imageNum == 0)
                {
                    currentPlayer.texture[0] = playerTextures[numOfPlayerTextures - 1];
                    currentPlayer.imageNum = numOfPlayerTextures;
                }
                else
                {
                    currentPlayer.imageNum--;
                    currentPlayer.texture[0] = playerTextures[currentPlayer.imageNum];
                }
            }

            
            if(currentPlayer.CheckInputButtons(controllerButtons.DRight))
            {
                if (currentPlayer.imageNum >= numOfPlayerTextures - 1)
                    {
                        currentPlayer.texture[0] = playerTextures[0];
                        currentPlayer.imageNum = 0;
                    }
                    else
                    {
                        currentPlayer.imageNum++;
                        currentPlayer.texture[0] = playerTextures[currentPlayer.imageNum];
                    }
                }
            }

        //Choosing the player 
        private void ChooseImageAI(Player currentPlayer)
        {
            int temp=0;
            temp = random.Next(0, numOfPlayerTextures);
            currentPlayer.texture[0] = playerTextures[temp];
        }

        //Sets up the initalizes the game data
        private void InitializeGame()
        {
            currentGameState = gameState.startTurn;
            currentScreen = new GameplayScreen();
            currentScreen.texture[0] = screenTextures[0];
            playersTurn = 1;
            player[0].currentPlayerState = Player.playerState.playersTurn;
            player[0].characterDisplayData(titleSafe, titleSafe);
            player[0].name = "Player 1";
            player[0].level = 1;
            player[1].currentPlayerState = Player.playerState.helpsFirst;
            player[1].characterDisplayData(titleSafe, titleSafe);
            player[1].name = "Player 2";
            player[1].level = 1;
            player[2].currentPlayerState = Player.playerState.helpsSecond;
            player[2].characterDisplayData(titleSafe, titleSafe);
            player[2].name = "Player 3";
            player[2].level = 1;
            player[3].currentPlayerState = Player.playerState.helpsThird;
            player[3].characterDisplayData(titleSafe, titleSafe);
            player[3].name = "Player 4";
            player[3].level = 1;
            for (int i = 0; i < numOfMonsters; i++)
            {
                monsters[i] = GenerateMonster(random);
                //monsters[i] = new YoungDragonDark(monsterTextures);
                monsters[i].SetLevel(random);
            }
            currentMonster = 0;
        }

        //Randomly generates Monsters
        private Monster GenerateMonster(Random rand)
        {
            int monsterIndex = rand.Next(0, possibleMonsters);
            switch (monsterIndex)
            {
                case 0:
                    return new Dragon(monsterTextures);
                case 1:
                    return new DragonDark(monsterTextures);
                case 2:
                    return new Faerie(monsterTextures);
                case 3:
                    return new Giant(monsterTextures);
                case 4:
                    return new HighClassToad(monsterTextures);
                case 5:
                    return new Hydra(monsterTextures);
                case 6:
                    return new Larva(monsterTextures);
                case 7:
                    return new Minotaur(monsterTextures);
                case 8:
                    return new Ogre(monsterTextures);
                case 9:
                    return new Raven(monsterTextures);
                case 10:
                    return new Skeleton(monsterTextures);
                case 11:
                    return new Toad(monsterTextures);
                case 12:
                    return new Wolf(monsterTextures);
                case 13:
                    return new YoungDragon(monsterTextures);
                case 14:
                    return new YoungDragonDark(monsterTextures);
                case 15:
                    return new Zombie(monsterTextures);
                default:
                    return new Toad(monsterTextures);
            }
        }

        //Takes players from the end of one turn to the beggining of the next turn
        private void MoveOn()
        {
            currentGameState = gameState.startTurn;
            currentScreen = new GameplayScreen();
            currentScreen.texture[0] = screenTextures[0];

            if (playersTurn < 4)
            {   
                playersTurn++;
            }
            else
            {
                playersTurn = 1;
            }
            for (int i = 0; i < player.Length; i++)
            {
                player[i].done = false;
            }
     
            if (currentMonster < numOfMonsters-1)
            {
                currentMonster++;
            }
            else
            {
                currentMonster = 0;
            }    
        }

        //Pauses
        public void Pause()
        {
            for (int i = 0; i < player.Length; i++)
            {
                if (player[i].CheckInputButtons(controllerButtons.Start))
                {
                    paused = true;
                }
            }
            if (paused == true)
            {
                Unpause();
            }

        }

        //Unpauses or sends game back to the beggining
        public void Unpause()
        {
            for (int i = 0; i < player.Length; i++)
            {
                if (player[i].CheckInputButtons(controllerButtons.B))
                {
                    currentGameState = gameState.mainMenu;
                    currentScreen = new MainScreen();
                    currentScreen.texture[0] = screenTextures[3];
                }
            }
            
            for (int i = 0; i < player.Length; i++)
            {
                if (player[i].CheckInputButtons(controllerButtons.A))
                {
                    paused = false;
                }
            }
        }

        //Sends players back to the beggining of the game
        public void Endgame()
        {

            for (int i = 0; i < player.Length; i++)
            {
                if(player[i].CheckInputButtons(controllerButtons.A))
                {
                    currentGameState = gameState.mainMenu;
                    currentScreen = new MainScreen();
                    currentScreen.texture[0] = screenTextures[3];
                }

            }
        }
    }
}

